struct None {}

// not named `Option` to avoid conflicts with the built-in type:
type MyOption<T> = Error | None | T

fn unwrap_if<T>(o MyOption<T>) T {
	if o is T {
		return o
	}
	panic('no value')
}

fn unwrap_match<T>(o MyOption<T>) string {
	match o {
		None {
			return 'none'
		}
		Error {
			return 'none'
		}
		T {
			return 'value'
		}
	}
}

fn test_generic_sumtype_unwrapping() {
	y := MyOption<bool>(false)

	assert unwrap_if(y) == false
	assert unwrap_match(y) == 'value'
}

fn test_generic_sumtype_auto_str() {
	x := MyOption<string>('hi')
	y := MyOption<bool>(None{})
	assert '$x, $y' == "MyOption<string>('hi'), MyOption<bool>(None{})"
}

struct Foo<T> {
	x T
}

struct Bar<T> {
	x T
}

type MyType<T> = Bar<T> | Foo<T>

fn test_generic_struct_members() {
	// TODO: this is currently needed to properly resolve that variant's type:
	_ = Bar<string>{''}

	f := Foo<string>{'hi'}
	t := MyType<string>(f)
	assert t.type_name() == 'Foo<string>'
	// accessing a field common to all variants, just like with a normal sumtype:
	assert t.x == 'hi'
}

type MultiGeneric<X, Y, Z> = X | Y | Z

fn test_multi_generic_type() {
	mut m := MultiGeneric<bool, int, string>(1234)
	m = 'hi'
	match m {
		bool {
			assert false
		}
		int {
			assert false
		}
		string {
			return
		}
	}
	assert false
}
